#include "symtable.h"

// table_add : ajoute un symbole à la table des symboles
//             (vérifie s'il est déjà dedans)
symtable* table_add(symtable* table, char* id, int type, char* addr)
{
	// On vérifie que le symbole n'est pas déjà présent	
	if (table_get_str(table, id) != NULL)
	{
		// TODO : gérer les erreurs
		yyerror((char*) g_strdup_printf("Erreur : la variable '%s' a déjà été déclaré\n", id));
		
		return table;
	}
	
	// Création d'un nouveau symbole
	symtable* n = malloc(sizeof(symtable));
	
	// Propriétés du symbole
	n->id = malloc((strlen(id)+1) * sizeof(char));
	n->id = strcpy(n->id, id);
	n->type = type;
	n->addr = malloc((strlen(addr)+1) * sizeof(char));
	n->addr = strcpy(n->addr, addr);
	n->debut = 0;
	n->next = NULL;
	
	
	// Ajout du symbole à la liste des symboles
	if (table == NULL)
	{
		n->index = 0;
		table = n;
	}
	else
	{
		n->index = table->index + 1;		
		n->next  = table;	
		table = n;
	}
	
	return table;
}

// table_add_identlist : ajoute une list d'identifiants à la table des symboles en fonction de leur type
//				(le type est identique pour tous les identifiants)
symtable* table_add_identlist(symtable* table, syntree* list, syntree* list_type)
{
	int   type  = list_type->_type.type;
	char* label = NULL;
	
	int i = 0;
	int j = 0;
	
	// Parcours de la liste
	syntree* node = list;
	do
	{	
		// Ajout à la table, si l'identifiant est de type tableau
		if (list_type->type == T_ARRAY)
		{
			label = (char*) g_strdup_printf("tab_%s", node->op.op[0]->id_str.str);
			table = table_add(table, node->op.op[0]->id_str.str, list_type->type, label);
			//g_strdup_printf permet d'écrire dans une variable dont la taille est allouée automatiquement
			data = gencode_add(data, "%s :", g_strdup_printf("%s", label));
			for(i = 0; i < list_type->array.nbDim; i++)
			{
				for(j = 0; j <= list_type->array.finTab - list_type->array.debutTab; j++)
				{
					data = gencode_add(data, "\t.word %d", 0);
				}
			}
		}
		// Ajout à la table, si l'identifiant est une variable de type simlpe
		else
		{
			label = (char*) g_strdup_printf("var_%s", node->op.op[0]->id_str.str);
			table = table_add(table, node->op.op[0]->id_str.str, type, label);
			data  = gencode_add(data, "%s : \n"
				                      "\t.word 0", label);
		}
		
		// Prochain noeud
		node = node->op.op[1]; 
		
	}while (node != NULL);// && node->op.op[0]->id_str.str != NULL);
	
	return table;
}

//table_mod : permet de stocker l'indice de début du tableau dans l'arbre afin d'y avoir accès plus tard
symtable* table_mod_arraylist(symtable* table, syntree* list, int size)
{
	syntree* node = list;
	symtable* arr = NULL;
	
	//on parcourt la liste des identifiants
	while (node != NULL)
	{
		arr = table_get_str(table, node->op.op[0]->id_str.str);
		arr->debut = size;
		node = node->op.op[1];	
	}
	
	return table;
}

// table_get : récupère un symbole dans la table des symboles
//             (NULL si non trouvé)
symtable* table_get(symtable* table, int index)
{
	symtable* tmp = table;
	
	// Parcours de la table
	while (tmp != NULL)
	{
		if (tmp->index == index)
		{
			return tmp;
		}
		
		tmp = tmp->next;
	}
	
	// On arrive jusqu'ici, on ne l'a pas trouvé
	return NULL;
}

// table_get : récupère un symbole dans la table des symboles
//             (NULL si non trouvé)
symtable* table_get_str(symtable* table, char* id)
{
	symtable* tmp = table;
	
	// Parcours de la table
	while (tmp != NULL)
	{
		if (strcmp(tmp->id, id) == 0)
		{
			return tmp;
		}
		
		tmp = tmp->next;
	}
	
	// On arrive jusqu'ici, on ne l'a pas trouvé
	return NULL;
}

// table_print : affiche le contenu de la table des symboles
void table_print(symtable* table)
{
	symtable* tmp = table;
	
	// Parcours de la table
	while (tmp != NULL)
	{
		printf("%s : ", tmp->id);
		
		switch (tmp->type)
		{
			case T_INT:
				printf("int");
				break;
			
			case T_BOOL:
				printf("bool");
				break;
				
			
			case T_UNIT:
				printf("unit");
				break;
			
			case T_ARRAY:
				printf("array");
				break;
			
			default :
				printf("?");
		}
		
		printf("\n");
		
		tmp = tmp->next;
	}
}

// table_free : libère la mémoire utilisée par la table des symboles
void table_free(symtable* table)
{
	if (table == NULL) return;
	
	symtable* del = NULL;
	symtable* tmp = table;
	
	while (tmp != NULL)
	{
		free(tmp->id);
		free(tmp->addr);
		
		del = tmp;
		tmp = tmp->next;
		free(del);
	}
}
